package com.astrocsr.action.account;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import com.astrocsr.action.BaseAction;
import com.astrocsr.business.AuditLogManager;
import com.astrocsr.business.SecurityListManager;
import com.astrocsr.business.StatementManager;
import com.astrocsr.business.SystemManager;
import com.astrocsr.business.UserManager;
import com.astrocsr.common.Constants;
import com.astrocsr.common.helper.ContextHelper;
import com.astrocsr.common.helper.EncryptionHelper;
import com.astrocsr.domain.db.PagingInfo;
import com.astrocsr.domain.db.SearchResult;
import com.astrocsr.domain.model.AccountModel;
import com.astrocsr.domain.web.GroupAccount;
import com.astrocsr.domain.web.GroupInfo;
import com.astrocsr.domain.web.ParametersInfo;
import com.astrocsr.domain.web.UserInfo;
import com.opensymphony.xwork2.ModelDriven;

/**
 * 
 * @author Created Jan 08, 2014
 */
@Controller("accountAction")
@Scope("prototype")
public class AccountAction extends BaseAction implements
		ModelDriven<AccountModel> {

	private static final long serialVersionUID = 1L;
	private AccountModel model = new AccountModel();

	public AccountModel getModel() {
		return model;
	}

	@Autowired
	private UserManager userManager;
	@Autowired
	private SystemManager systemManager;
	@Autowired
	private SecurityListManager securityManager;
	@Autowired
	private StatementManager statementManager;
	private @Autowired
	AuditLogManager auditLogManager;

	static final Logger log = Logger.getLogger(AccountAction.class);
	
	/**
	 * List User
	 */
	public String initUser() throws Exception {
		try {
			
			String startGroupCode = ContextHelper.getCurrentRole();
			if (StringUtils.isNotBlank(startGroupCode)) { 
				List<GroupInfo> groupInfoList = securityManager.listGroupByParentCode(startGroupCode);
				model.setGroupInfoList(groupInfoList);
			}
			
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
	
	/******************    AJAX     *******************/
	
	/**
	 * Search User
	 */
	public String executeSearchUser() throws Exception {
		try {
			PagingInfo pagingInfo = model.getPagingInfo();
			if (pagingInfo == null) {
				pagingInfo = new PagingInfo();
			}
			
			SearchResult<UserInfo> userInfoList = userManager.listUser(ContextHelper.getCurrentRole(),  model.getUserInfo(), pagingInfo);
			model.setUserInfoList(userInfoList);
			if (userInfoList != null) {
				model.setUserInfoList(userInfoList);
				
				// insert log
				auditLogManager.addAuditlog(
						Constants.LOG_ACCT_TYPE_ACTIVITY,	//0
						Constants.LOG_ActCode_User_SER, 	//1 
						Constants.LOG_ActName_User_SER, 	//2
						ContextHelper.getLoginId(), 		//3
						ContextHelper.getCurrentRole(), 	//4
						"Search User", //5
						request.getRemoteAddr()				//6
						);
				
				if (userInfoList.getPagingInfo() != null) {
					model.setPagingInfo(userInfoList.getPagingInfo());
				} else {
					pagingInfo = new PagingInfo();
					pagingInfo.setTotal(userInfoList.size());
					model.setPagingInfo(pagingInfo);
				}
			}
			
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
	
	/**
	 * Add User
	 */
	public String executeAddUser() throws Exception {
		try {
			String email 	 = model.getEmail();
			String password  = model.getPassword();
			String groupCode = model.getGroupCode();

			if (validateAddUser(email, password, groupCode)) {
				if (!userManager.checkExistedUser(email)) {
					UserInfo userInfo = new UserInfo();
					userInfo.setEmail(email);
					userInfo.setPassword(password);
					userInfo.setGroupCode(groupCode);
					userInfo.setLocked(Constants.NO);
					userInfo.setEnabled(Constants.YES);
					userInfo.setCreatedBy(ContextHelper.getLoginId());
					userManager.addUser(userInfo);
					model.setSuccessMessage(getText("user.add.success"));
					
					// insert log
					auditLogManager.addAuditlog(
							Constants.LOG_ACCT_TYPE_ACTIVITY,	//0
							Constants.LOG_ActCode_User_Add, 	//1 
							Constants.LOG_ActName_User_Add, 	//2
							ContextHelper.getLoginId(), 		//3
							ContextHelper.getCurrentRole(), 	//4
							"Add User; email: " + email + "; groupCode: " + groupCode, //5
							request.getRemoteAddr()				//6
							);
				} else {
					model.setFailMessage(getText("user.add.existedemail"));
				}
			} else {
				System.out.println("email 	 	= " + email);
				System.out.println("password 	= " + password);
				System.out.println("groupCode 	= " + groupCode);
				model.setFailMessage(getText("user.add.fail"));
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
	
	private boolean validateAddUser(String email, String password, String groupCode) {
		boolean result = true;
		
		if (StringUtils.isBlank(email)) {
			return false;
		}
		if (StringUtils.isBlank(password)) {
			return false;
		}
		if (StringUtils.isBlank(groupCode)) {
			return false;
		}		
		return result;
	}
	
	/**
	 * Update User
	 */
	public String executeUpdateUser() throws Exception {
		try {
			Long userId   	= model.getUserId();
			String email 	= model.getEmail();
			String password = model.getPassword();
			if (validateUpdateUser(userId, email, password)) {
				UserInfo userInfo = new UserInfo();
				userInfo.setUserId(userId);
				userInfo.setEmail(email);
				userInfo.setPassword(password);
				userManager.addUser(userInfo);
				model.setSuccessMessage(getText("user.add.success"));
				
				// insert log
				auditLogManager.addAuditlog(
						Constants.LOG_ACCT_TYPE_ACTIVITY,	//0
						Constants.LOG_ActCode_User_UPT, 	//1 
						Constants.LOG_ActName_User_UPT, 	//2
						ContextHelper.getLoginId(), 		//3
						ContextHelper.getCurrentRole(), 	//4
						"Update User; email: " + email, //5
						request.getRemoteAddr()				//6
						);
			} else {
				System.out.println("email 	 = " + email);
				System.out.println("password = " + password);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
	
	private boolean validateUpdateUser(Long userId, String email, String password) {
		boolean result = true;
		
		if (StringUtils.isBlank(email)) {
			return false;
		}

		if (StringUtils.isBlank(password)) {
			return false;
		}
		
		return result;
	}
	
	/**
	 * Delete User
	 */
	public String executeDeleteUser() throws Exception {
		try {
			Long userId   	= model.getUserId();
			if (userId != null) {
				userManager.deleteUser(userId);
				model.setSuccessMessage(getText("user.delete.success"));
				// insert log
				auditLogManager.addAuditlog(
						Constants.LOG_ACCT_TYPE_ACTIVITY,	//0
						Constants.LOG_ActCode_User_Add, 	//1 
						Constants.LOG_ActName_User_Add, 	//2
						ContextHelper.getLoginId(), 		//3
						ContextHelper.getCurrentRole(), 	//4
						"Delete User; userId: " + userId, //5
						request.getRemoteAddr()				//6
						);
			} else {
				model.setSuccessMessage(getText("user.delete.fail"));
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
	
	/**
	 * Reset User
	 */
	public String resetUser() throws Exception {
		log.info("resetUser.start");
		UserInfo userInfo = model.getUserInfo();
		try {
			// Get UserInfo from jsp screen
			if (userInfo != null && !StringUtils.isBlank(userInfo.getEmail())) {
				
				ParametersInfo paramMax = systemManager.getParameters(Constants.PARAM_NAME_TECH, Constants.PARAM_PWD_MAX_LEN);
				ParametersInfo paramMin = systemManager.getParameters(Constants.PARAM_NAME_TECH, Constants.PARAM_PWD_MIN_LEN);
				int pwdMaxLen = Constants.PARAM_PWD_MAX_LEN_DEFAULT;
				int pwdMinLen = Constants.PARAM_PWD_MIN_LEN_DEFAULT;
				if (paramMax != null && NumberUtils.isNumber(paramMax.getParamValue())) {
					pwdMaxLen = Integer.parseInt(paramMax.getParamValue());
				}
				if (paramMin != null && NumberUtils.isNumber(paramMin.getParamValue())) {
					pwdMinLen = Integer.parseInt(paramMin.getParamValue());
				}
				model.setPwdMaxLen(pwdMaxLen);
				model.setPwdMinLen(pwdMinLen);
				
				if ((userInfo.getUserId() == null) || !validateResetUser(userInfo)) {
					// get user detail (search)
					userInfo = userManager.getUserByEmail(userInfo.getEmail());
					if (userInfo != null) {
						
						// check allowed
						boolean isAllowed = userManager.checkAllowedGroup(userInfo.getGroupCode(), ContextHelper.getCurrentRole());
						if (!isAllowed) {
							addActionError(getText("user.resetpass.notallow"));
							model.setUserInfo(null);
							return INPUT;
						}
						
						model.setUserInfo(userInfo);
					} else {
						addActionError(getText("user.resetpass.nouser"));
						model.setUserInfo(null);
						return INPUT;
					}
				} else {

						// start reset
						boolean locked  = false;
						boolean enabled = false;
						if (BooleanUtils.toBoolean(userInfo.getLocked()))
							locked = true;
							
						if (BooleanUtils.toBoolean(userInfo.getEnabled()))
							enabled = true;

						// return message
						List<String> returnMsg = new ArrayList<String>();
						// old information
						UserInfo oldUserInfo = userManager.getUserById(userInfo.getUserId());
						// update new information
						userManager.resetUser(userInfo.getUserId(), userInfo.getGroupCode(), userInfo.getPasswordNew(), enabled, locked, ContextHelper.getLoginId(), returnMsg);
	
						// insert log
						auditLogManager.addAuditlog(
								Constants.LOG_ACCT_TYPE_ACTIVITY,	//0
								Constants.LOG_ActCode_User_UPT, 	//1 
								Constants.LOG_ActName_User_UPT, 	//2
								ContextHelper.getLoginId(), 		//3
								ContextHelper.getCurrentRole(), 	//4
								"Update User; email: " + userInfo.getEmail(), //5
								request.getRemoteAddr()				//6
								);
						
						// build success messges
						StringBuilder strReturnMsg = new StringBuilder();
						strReturnMsg.append(getText("user.resetpass.success"));
						if (returnMsg != null && returnMsg.size() > 0) {
							for (String value : returnMsg) {
								switch (value) {
									case "group" :
										strReturnMsg.append("<br/>");
										strReturnMsg.append(getText("user.resetpass.success."+value, new String[]{oldUserInfo.getGroupCode(), userInfo.getGroupCode()}));
										break;
									case "pwd" :
										strReturnMsg.append("<br/>");
										strReturnMsg.append(getText("user.resetpass.success."+value));
										break;
									default:
										strReturnMsg.append("<br/>");
										strReturnMsg.append(getText("user.resetpass.success."+value, new String[]{userInfo.getEmail()}));
										break;
								}
							}							
							
							addActionMessage(strReturnMsg.toString());
						}
						model.setUserInfo(null);
				}
			} else {
				// check empty login id
				return INPUT;
			}
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
			throw ex;
		}
		log.info("resetUser.end");
		return SUCCESS;
	}
	private boolean validateResetUser(UserInfo userInfo) {
		
		if (StringUtils.isBlank(userInfo.getEmail())) {
			return false;
		}
		
		if (!StringUtils.isBlank(userInfo.getPasswordNew()) && !StringUtils.isBlank(userInfo.getPasswordVer())
				&& !userInfo.getPasswordNew().equals(userInfo.getPasswordVer())) {

				// new password and confirm password are not matched
			addActionError(getText("user.resetpass.notmatch.newconfirm")); 
				return false;

		}
		return true;
	}

	/* Account */
	
	/**
	 * Init Account
	 */
	public String initAccount() throws Exception {
		try {

		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
	/**
	 * Search Account
	 */
	public String executeSearchAccount() throws Exception {
		try {
			PagingInfo pagingInfo = model.getPagingInfo();
			if (pagingInfo == null) {
				pagingInfo = new PagingInfo();
			}
			
			String currentGroupCode = ContextHelper.getCurrentRole();
			SearchResult<GroupAccount> groupAccountList = null;
			
			groupAccountList = statementManager.listGroupAccountByGroupCode(currentGroupCode, model.getAccountInfo(), pagingInfo);
			model.setGroupAccountList(groupAccountList);

			if (groupAccountList != null) {
				if (groupAccountList.getPagingInfo() != null) {
					model.setPagingInfo(groupAccountList.getPagingInfo());
				} else {
					pagingInfo = new PagingInfo();
					pagingInfo.setTotal(groupAccountList.size());
					model.setPagingInfo(pagingInfo);
				}
			}
			
			// insert log
			auditLogManager.addAuditlog(
					Constants.LOG_ACCT_TYPE_ACTIVITY,	//0
					Constants.LOG_ActCode_Account_SER, 	//1 
					Constants.LOG_ActName_Account_SER, 	//2
					ContextHelper.getLoginId(), 		//3
					ContextHelper.getCurrentRole(), 	//4
					"Search Account", //5
					request.getRemoteAddr()				//6
					);

		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
	
	/**
	 * Assign Account
	 */
	public String executeAssignAccount() throws Exception {
		try {
			String selectedAccountNo = model.getSelectedAccountNo();
			String selectedGroupCode = model.getSelectedGroupCode();

			if (StringUtils.isNotBlank(selectedAccountNo) && StringUtils.isNotBlank(selectedGroupCode)) {
				if (!userManager.checkAssignedAccount(selectedAccountNo, selectedGroupCode)) {
					userManager.addGroupAccount(selectedAccountNo, selectedGroupCode, ContextHelper.getLoginId());
					model.setSuccessMessage(getText("assign.add.success"));

					// insert log
					auditLogManager.addAuditlog(
							Constants.LOG_ACCT_TYPE_ACTIVITY,	//0
							Constants.LOG_ActCode_Account_Assign, 	//1 
							Constants.LOG_ActName_Account_Assign, 	//2
							ContextHelper.getLoginId(), 		//3
							ContextHelper.getCurrentRole(), 	//4
							"Assign Account", //5
							request.getRemoteAddr()				//6
							);
				} else {
					model.setFailMessage(getText("assign.add.existed"));
				}
			} else {
				model.setFailMessage(getText("assign.add.fail"));
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}

	/**
	 * Search Remain Group
	 */
	public String executeSearchRemainGroup() throws Exception {
		try {
			String selectedAccountNo = model.getSelectedAccountNo();

			if (StringUtils.isNotBlank(selectedAccountNo)) {
				selectedAccountNo = EncryptionHelper.decrypt(selectedAccountNo);
				// get all group by parent (current group)
				List<GroupInfo> groupInfoList = securityManager.listGroupByParentCode(ContextHelper.getCurrentRole());
				List<GroupAccount> assignedGroupInfoList = null;
				if (groupInfoList != null && groupInfoList.size() > 0) {
					
					// get all groups that have been assigned to the selected account
					List<GroupAccount> groupAccountList = statementManager.listGroupAccountByAccountNo(selectedAccountNo);
					
					GroupInfo groupInfo    = null;
					GroupAccount groupAccountTmp = null;
					if (groupAccountList != null && groupAccountList.size() > 0) {
						assignedGroupInfoList = new ArrayList<GroupAccount>();
						for (GroupAccount groupAccount : groupAccountList) {
							for (int i=0; i < groupInfoList.size(); i++) {
								groupInfo = groupInfoList.get(i);
								if (groupInfo.getGroupCode().equals(groupAccount.getGroupCode())) {
									// add assigned to list
									groupAccountTmp = new GroupAccount();
									groupAccountTmp.setGroupAccountId(groupAccount.getGroupAccountId());
									groupAccountTmp.setAccountNo(groupAccount.getAccountNo());
									groupAccountTmp.setGroupCode(groupInfo.getGroupCode());
									groupAccountTmp.setGroupName(groupInfo.getGroupName());

									assignedGroupInfoList.add(groupAccountTmp);
									// remove assigned from list
									groupInfoList.remove(i);
									break;
								}
							}
						}
					}
				}
				model.setGroupInfoList(groupInfoList);
				model.setAssignedGroupInfoList(assignedGroupInfoList);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
	
	/**
	 * Delete Group Account
	 */
	public String executeDeleteGroupAccount() throws Exception {
		try {
			Long groupAccountId   	= model.getGroupAccountId();
			if (groupAccountId != null) {
				securityManager.deleteGroupAccount(groupAccountId);
				model.setSuccessMessage(getText("assign.delete.success"));
				
				// insert log
				auditLogManager.addAuditlog(
						Constants.LOG_ACCT_TYPE_ACTIVITY,	//0
						Constants.LOG_ActCode_Account_Remove, 	//1 
						Constants.LOG_ActName_Account_Remove, 	//2
						ContextHelper.getLoginId(), 		//3
						ContextHelper.getCurrentRole(), 	//4
						"Remove account assignment", //5
						request.getRemoteAddr()				//6
						);
			} else {
				model.setSuccessMessage(getText("assign.delete.fail"));
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
		return SUCCESS;
	}
}